/*
 * Copyright @ 苏州瑞云信息技术有限公司 All rights reserved.
 */
package work.thread_eg.thread0;

import lombok.SneakyThrows;

import java.util.concurrent.*;

/**
 *
 * 原生线程类的三种实现方式
 *
 * 注意
 *      run()方法是没有返回值的
 *      call()是有返回值的 使用 Future接口的实现类获取返回结果
 *
 */
public class ThreadTest02 {
    public static void main(String[] args) {
        ThreadTest02 threadTest02 = new ThreadTest02();

        threadTest02.myCallable();
    }

    public void myThread() {
        // 1、继承Thread类实现线程
        // 创建线程类对象
        MyThread mt1 = new MyThread("线程A ");
        MyThread mt2 = new MyThread("线程B ");
        // 启动线程
        mt1.start();
        mt2.start();
    }

    public void myRunnable() {
        // 2、实现Runnable接口
        MyRunnable myRunnable1 = new MyRunnable(1);
        MyRunnable myRunnable2 = new MyRunnable(2);
        new Thread(myRunnable1).start();
        new Thread(myRunnable2).start();
    }

    /**
     * Callable接口的实现类是真正的线程主体逻辑实现类
     * FutureTask是用于存放线程执行返回结果的类
     * Thread是线程启动的类
     *
     * 一个线程执行之后对应一个返回结果 所以也就对应着一个FutureTask对象
     * 也就是说  Thread对象和FutureTask对象是一对一关系
     * 但是多个FutureTask可以使用同一个Callable接口的实现对象
     * 表示多个线程执行的是同一个对象的内容
     *
     */
    public void myCallable() {
        // 3、实现Callable<> 有返回值
        MyCallable myCallable1 = new MyCallable(5);
        MyCallable myCallable2 = new MyCallable(10);

        // 1 通过Callable接口的实现类 创建FutureTask对象
        FutureTask<Integer> futureTask1 = new FutureTask<>(myCallable1);
        FutureTask<Integer> futureTask2 = new FutureTask<>(myCallable2);

        // 2 通过FutureTask对象创建Thread类 并且执行
        new Thread(futureTask1, "Thread-001").start();
        // 为什么这样子不执行
        new Thread(futureTask2, "Thread-002").start();
        // 返回值
        try {
            // 获取异步结果
            Integer integer1 = futureTask1.get();
            System.out.println("线程1 返回值 ：" + integer1);
            Integer integer2 = futureTask2.get();
            System.out.println("线程2 返回值 ：" + integer2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 方式一 继承Thread类，作为线程的实现类
     */
    class MyThread extends Thread {
        // 表示线程的名称
        private String name;

        // 通过构造方法配置name属性
        public MyThread(String name) {
            this.name = name;
        }

        /**
         * 覆写run()方法，作为线程 的操作主体
         */
        @SneakyThrows
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(name + "运行，i = " + i);
            }
        }
    }


    /**
     * 方式二 实现Runnable接口
     */
    class MyRunnable implements Runnable {
        private int taskNum;

        public MyRunnable(int num) {
            this.taskNum = num;
        }

        @SneakyThrows
        @Override
        public void run() {
            System.out.println("正在执行task " + taskNum);
            TimeUnit.SECONDS.sleep(1);
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "运行，i = " + i);
            }
            System.out.println("task " + taskNum + "执行完毕");
        }
    }

    /**
     * 方式三 实现Callable接口
     * call()有返回值的
     *
     */
    class MyCallable implements Callable<Integer> {

        private Integer num;

        public MyCallable(Integer num) {
            this.num = num;
        }

        @Override
        public Integer call() throws Exception {
            String ThreadName = Thread.currentThread().getName();
            int sum = 0;
            for (int i = 0; i < num; i++) {
                System.out.println(ThreadName + " 运行:" + i);
                sum += i;
            }
            return sum;
        }
    }
};

